#ifndef MYDATABASE_H
#define MYDATABASE_H

#include <QObject>
#include <QSqlDatabase>
#include <QStandardItemModel>
#include <QTableView>
#include <QTimer>
#include <QSqlError>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QString>
#include <QByteArray>
#include <QMutex>
#include <QStringList>
#include <QVariant>
#include <QHeaderView>
#include "AddMyPushButton.h"
#include "CellDataFormat.h"
#include "Logger.h"
#include "MultiFilterProxy.h"


#pragma execution_character_set("utf-8")

struct TableViewData
{
    QString sql;
    QStringList HeaderList;
    QTableView* table;
    QList<IconNumber> IconNum;
    QMap<QString, CellType> cellDataFormat;
    bool is_true = true;
};


//数据库操作
class MyDatabase: public QWidget
{
    Q_OBJECT
public:

    /**
     * @brief 获取MyDatabase单例实例
     * @return MyDatabase实例指引
     */
    static MyDatabase& getInstance();

    /**
     * @brief  去除字符串所有空格
     * @param  str 需要去除空格的字符串
     */
    void remove_all_spaces(std::string &str);

    /**
     * @brief 关闭数据库
     */
    void closeDatabase();

    /**
     * @brief  判断数据库连接
     * @return 是否连接成功
     */
    bool openDatabase();

    /**
     * @brief  外界修改数据库配置参数，判断新参数是否能连接数据库
     * @param  infomap 存放数据库参数的map容器
     * @return 是否连接成功
     */
    bool AlterDatabase(const QMap<QString, QVariant> &infomap);

    /**
     * @brief  查询数据库表
     * @param  sql 一条完整的查询sql语句
     * @return 返回包含查询结果的数据结构dataList
     */
    QList<QStringList> query_table(const QString &sql);

    /**
     * @brief  查询数据库表
     * @param  fields 需要查询的以','为分隔符的多个表字段名
     * @param  tablename 需要查询表名
     * @return 返回包含查询结果的数据结构dataList
     */
    QList<QStringList> query_some_tabledata(const QString &fields, const QString &tablename, const QString &id = "");

    /**
     * @brief  判断表中主键是否已存在
     * @param  tableName 表名
     * @param  primaryKeyValue 需要判断的主键
     * @return 返回主键是否冲突
     */
    bool isPrimaryKeyExists(const QString &tableName, int primaryKeyValue);

    /**
     * @brief  为每个新TableView添加对应的模型以及TableViewData结构体
     * @param  tableName 表名
     * @param  mytableData 存放sql语句、表头列表、QTableView对象指针和需添加功能按键索引的结构体
     */
    void addTableMonitor(const QString &tableName, TableViewData &mytableData);

    /**
     * @brief  对model模型更新数据
     * @param  model QStandardItemModel模型对象指针
     * @param  mytableData 存放sql语句、表头列表、QTableView对象指针和需添加功能按键索引的结构体
     * @param  rowcount 表格行数
     * @param  colcount 表格列数
     * @param  dataList 存放数据库表读取的数据列表
     */
    void tableDataRefresh(QStandardItemModel *model,
                          const TableViewData &mytableData,
                          const int &rowcount,
                          const int &colcount,
                          const QList<QStringList> &dataList);

    /**
     * @brief  刷新某张表数据
     * @param  tableName 表名
     */
    void refreshTable(const QString &tableName, const QString& new_sql = "");

    /**
     * @brief  定时器的开启和关闭
     */
    void startTimer(const QString &tableName);
    void stopTimer(const QString &tableName);

    /**
     * @brief  赛选显示表数据
     * @param  data 需要显示的行
     * @param  tableName 表名
     */
    void setProxy(QMap<int,bool> &data, QString tablenanme);

signals:
    /**
     * @brief  数据发生变化时发送信号
     */
    void tableDataChanged(const QString &);

    /**
     * @brief  添加单元格功能按键信号
     */
    void setButton(QStandardItemModel*, QTableView*, const QList<IconNumber>&, const int&);

public slots:
    /**
     * @brief  QStandardItemModel模型数据变动时触发的槽函数
     */
    void onModelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles);

    /**
     * @brief  为每个新TableView添加对应的模型以及TableViewData结构体
     * @param  tableView 控件tableView对象指针
     * @param  model 模型QStandardItemModel对象指针
     */
    void updateTableWidget(QTableView *tableWidget, QStandardItemModel *model, const QString& new_sql = "");

private:
    QSqlDatabase    m_db;
    static QMutex   m_mutex;

    QMap<QString, QStandardItemModel*> m_models;
    QMap<QString, TableViewData> m_tableWidgets;
    QMap<QString, QTimer*> m_refreshTimers;

    //数据库参数
    QString ip;
    int     port;
    QString dbname;
    QString username;
    QString password;

    explicit MyDatabase(QWidget *parent = nullptr);
    ~MyDatabase();
    MyDatabase(const MyDatabase&) = delete;
    MyDatabase& operator=(const MyDatabase&) = delete;

};



#endif // MYDATABASE_H
